class XPromise{
  static PENDING = 'pending'
  static RESLOVE = 'reslove'
  static REJECT = 'reject'
  constructor(func){
    this.status = XPromise.PENDING
    this.value = null
    this.callBack = []
    /*
      函数是拥有bind方法，传递一个新的this对象，返回一个函数的复制，同时这个复制的函数的this是修改了传递对象为上下文的函数对象
    */ 
    try {
      func(this.reslove.bind(this),this.reject.bind(this))
    } catch (error) {
      this.reject(error.message)
    }
  }

  reslove(value){
    
    /*
      在外部构造函数调用，这里的this指向的本来应该是window，因为是类 使用的是严格模式 会变成undefined，所以得不到
        我们想要的结果，所以可以使用bind强制修改this的绑定
    */ 
    if(this.status === XPromise.PENDING){
      this.value = value
      this.status = XPromise.RESLOVE
    }
    /*
      只要是执行到 then方法里面的 onreslove 或者是 onreject 方法 说明一定是异步的
        所以这里也先用 setTimeOut 来处理
    */ 
    setTimeout(() => {
      this.callBack.map(item=>{
        item.onreslove(this.value)
      })
    });
    
  }

  reject(reason){
    if(this.status === XPromise.PENDING){
      this.value = reason
      this.status = XPromise.REJECT
    }
    setTimeout(() => {
      this.callBack.map(item=>{
        item.onreject(this.value)
      })
    });

  }

  then(onreslove,onreject){
    return new XPromise((reslove,reject)=>{
      /*
        如果没有传递函数，就自己封装一个函数，不至于报错种植运行
      */ 
      if(typeof onreslove !== 'function'){
        /* 当没传递 onreslove 的时候，打印onreslove位 undefined  typeof undefined 的结果 也是undefined  所以这里只需要检查 typeof onreslove !== 'function' 就可以排除其他所有的情况了 */
        onreslove = ()=> this.value
      }
      if(typeof onreject !== 'function'){
        /* 这个是为了解决then的代码穿透问题， 当then没有传递任何参数的时候  只需要把值返回 给下一个then的promise处理即可 */ 
        onreject = ()=>this.value
      }
      if(this.status === XPromise.PENDING){
        this.callBack.push({
          onreslove:value=>{
            try {
              // console.log('mpv')
              let result = onreslove(value)
              // console.log('mpv2')

              if(result instanceof XPromise){
                // 在then中返回的是一个 prmise对象
                result.then(res=>{
                  // console.log('解开了',res)
                  reslove(res)
                },err=>{
                  reject(err)
                })
              }else{
                reslove(result)
              }
              // console.log('sss')
            } catch (error) {
              // console.log('kkk')
              /*
                与大盘catch的错误就不需要再继续往后走了，因为没有意义，只有用户自己返回的才有必须链式操作下去
              */ 
              reject(error.message) // then 发生的错误 应该是由下一个 promise 的 then来接收 所以是 reject 不是 onreject
            }
            
          },
          onreject:reason=>{
            try {
              let result = onreject(reason)
              reslove(result)
            } catch (error) {
              reject(error.message)
            }
          }
        })
      }
      if(this.status === XPromise.RESLOVE){
        /*
          then 方法是异步的，我们可以把它封装到 暂时这里就先把它封装到 setTimeout宏任务队列里，后期再改装成微任务队列
        */ 
        setTimeout(() => {
          try {
            let result = onreslove(this.value)
            if(result instanceof XPromise){
              // 在then中返回的是一个 prmise对象
              /*
                promise的用法是 在 then默认返回的是一个primise，但是其实我们是可以手动自己写一个promise返回的
              */ 
              result.then(res=>{
                reslove(res)
              },err=>{
                reject(err)
              })
            }else{
              reslove(result)
            }
          } catch (error) {
            /*
              只要有错误，就将错误抛给 onreject来处理，就可以捕获到错误了
            */
            reject(error.message)
          }
        }, 0);
      }else if(this.status === XPromise.REJECT){
        setTimeout(() => {
          try {
            let result =  onreject(this.value)
            if(result instanceof XPromise){
              // 在then中返回的是一个 prmise对象
              result.then(res=>{
                reslove(res)
              },err=>{
                reject(err)
              })
            }else{
              reslove(result)
            }
          } catch (error) {
            reject(error.message)
          }
        }, 0);
      }
    })
  }
}

export default XPromise